#include <sstream>
#include <SypX/SypX.h>

#ifdef SYPX_MEMCHECK
#include "mmgr.h"
#endif

#include "MenuScene.h"
#include "MissionScene.h"
#include "SelectionScene.h"
#include "SheepDefenceApp.h"

namespace SheepDefence
{
	MissionScene::MissionScene(SypX::Font* f, int level, int breed, int score, int stars) : level(level), mousedown(false), anchor_x(0.0f), curr_x(0.0f), updateBreed(breed), updateScore(score), updateGrade(stars)
	{
		font = f;
		page = level / 5;
	}

	MissionScene::~MissionScene(void)
	{
		delete bg;

		for (unsigned int i = 0; i < missions.size(); i++)
		{
			delete missions[i].go;

			for (unsigned int j = 0; j < 3; j++)
			{
				delete missions[i].stars[j];
				delete missions[i].icons[j];
			}
		}
		
		delete back;
		
		engine->getAudioEngine()->deleteSoundBuffer(snd);
		
	}

	void MissionScene::init()
	{
		
		engine = SypX::Engine::getSingleton();
		render = engine->getRenderer();
		canvas = engine->getCanvas();	
		if(!font)
		{
			font = engine->loadFontFromFile("Fonts/sheepFont.ttf", 24, 3);
		}

		bgMesh = new SypX::Mesh();
		bgMesh->initAsQuad(320.0f,480.0f);
		
		bgTex = SypX::Texture::loadFromFile("Textures/bgMission.png");
		
		bg = new SypX::MeshInstance();
		bg->useMesh(bgMesh);
		bg->useTexture(bgTex);

		bg->setPosition(SypX::Vec2(160.0f, 240.0f));
		
		render->setClearScreenColor(SypX::Vec4(0.0f, 0.0f, 0.0f, 1.0f));		
		
		snd = engine->getAudioEngine()->loadFromWAVFile("Sounds/Sega.wav");
		//engine->getAudioEngine()->playSound(snd, SypX::Vec3()) ;

		backTex = SypX::Texture::loadFromFile("Textures/btnBack.png");
		back = new SypX::Button(160.0f, 80.0f, 80.0f, 30.0f, 0.9f, backTex);
		back->onDownCallBack = SYPXBIND(&MissionScene::goBack, this, SYPX_ARG1, SYPX_ARG2);

		starMesh = new SypX::Mesh();
		starMesh->initAsQuad(50.0f,16.0f);

		stars.push_back(SypX::Texture::loadFromFile("Textures/Stars0.png"));
		stars.push_back(SypX::Texture::loadFromFile("Textures/Stars1.png"));
		stars.push_back(SypX::Texture::loadFromFile("Textures/Stars2.png"));
		stars.push_back(SypX::Texture::loadFromFile("Textures/Stars3.png"));

		dogMesh = new SypX::Mesh();
		dogMesh->initAsQuad(16.0f, 16.0f);

		dogs.push_back(SypX::Texture::loadFromFile("Textures/terrier.png"));
		dogs.push_back(SypX::Texture::loadFromFile("Textures/collie.png"));
		dogs.push_back(SypX::Texture::loadFromFile("Textures/greyhound.png"));
		
		if (level == 0)
			page = loadProfile();
		else
			loadProfile();

		curr_x = page * 320.0f;
	}

	int MissionScene::loadProfile()
	{
		SypX::FileInputStream fin;
		SypX::FileOutputStream fout;
		bool enabled = true;
		int last = 0, total;
		
		SypX::String path = SypX::Engine::getFilePath("Profile/player.pfl");
		fin.open(path.c_str());		//load level file

		fin >> total;		// total number of levels

		for (int i = 0; i < total; i ++)
		{
			std::ostringstream oss;
			oss << (i + 1);
			mission temp;
			
			fin >> temp.scores[0];	// terrier
			fin >> temp.grades[0];
			fin >> temp.scores[1];	// collie
			fin >> temp.grades[1];
			fin >> temp.scores[2];	// greyhound
			fin >> temp.grades[2];

			if (level == i + 1 && temp.scores[updateBreed] < updateScore)
			{
				temp.scores[updateBreed] = updateScore;
				temp.grades[updateBreed] = updateGrade;
			}
				
			if (temp.scores[0] + temp.scores[1] + temp.scores[2] != 0)
			{
				temp.enabled = true;
				enabled = true;
			}
			else if (enabled)
			{
				last = i;
				temp.enabled = true;
				enabled = false;
			}
			else
			{
				temp.enabled = false;
				oss << "d";
			}

			temp.x = 100.0f + floor((float) i / 5) * 320.0f;
			temp.y = (float) (5 - i % 5) * 55 + 75;
			temp.tex = SypX::Texture::loadFromFile("Textures/btn" + oss.str() + ".png");
			//temp.tex = SypX::Texture::loadFromFile("Textures/btnMore.png");
			temp.go = new SypX::Button(temp.x, temp.y, 50.0f, 50.0f, 0.9f, temp.tex);

			if (temp.enabled)
				temp.go->onDownCallBack = SYPXBIND(&MissionScene::goPlay, this, SYPX_ARG1, SYPX_ARG2);

			for (int j = 0; j < 3; j++)		// NOTE: CANNOT USE UNSIGNED BECAUSE LATER, USING j - 1
			{
				temp.stars[j] = new SypX::MeshInstance();
				temp.stars[j]->useMesh(starMesh);
				temp.stars[j]->useTexture(stars[temp.grades[j]]);
				temp.stars[j]->setPosition(SypX::Vec3(temp.stars[j]->getPositionRef().x, temp.y - (j - 1) * 16.0f, 0.9f));
			//	temp.stars[j]->getPositionRef().y = temp.y - (j - 1) * 16.0f;
			//	temp.stars[j]->getPositionRef().z = 0.9f;

				temp.icons[j] = new SypX::MeshInstance();
				temp.icons[j]->useMesh(dogMesh);
				temp.icons[j]->useTexture(dogs[j]);
				temp.icons[j]->setPosition(SypX::Vec3( temp.icons[j]->getPositionRef().x ,temp.y - (j - 1) * 16.0f, 0.9f));
				//temp.icons[j]->getPositionRef().y = temp.y - (j - 1) * 16.0f;
				//temp.icons[j]->getPositionRef().z = 0.9f;
			}

			missions.push_back(temp);
		}

		fout.open(path.c_str());
		fout << missions.size() << "\n";

		std::vector<mission>::iterator k = missions.begin();

		while (k != missions.end())
		{
			for (unsigned int j = 0; j < 3; j++)
			{
				fout << (*k).scores[j] << "\n";
				fout << (*k).grades[j] << "\n";
			}

			k++;
		}
		
		return (int) floor((float) last / 5);
	}

	void MissionScene::handleInput()
	{
		SypX::Event e = canvas->getEvent();
		
		if (back->processInput(e))
			return;

		std::vector<mission>::iterator i = missions.begin();

		while (i != missions.end())
		{
			if ((*i).go->processInput(e))
				return;
			i++;
		}

		switch (e.type)
		{
		case SypX::TOUCHDOWN:
		case SypX::MOUSELEFTDOWN:
			if (!mousedown)
			{
				if (anchor_x != curr_x)		// previous transition not complete, resume mousedown control
				{
					anchor_x = anchor_x - curr_x + (float) e.location.x;
					curr_x = (float) e.location.x;
				}
				else	// fresh swipe
				{
					anchor_x = (float) e.location.x;
					curr_x = anchor_x;
				}
				
				mousedown = true;
			}
			break;
		case SypX::TOUCHUP:
		case SypX::MOUSELEFTUP:
			mousedown = false;
			break;
		case SypX::TOUCHMOVE:
		case SypX::MOUSEMOVE:
			if (mousedown)
			{
				curr_x = (float) e.moved.curr.x;
			}
			break;
		}
	}

	void MissionScene::draw(float time)
	{
		std::vector<mission>::iterator i = missions.begin();

		while (i != missions.end())
		{
			if (!mousedown && anchor_x > curr_x)	// left swipe
			{
				if (anchor_x - curr_x < 1.0f)	// back to original page
					curr_x = anchor_x;
				else if (anchor_x - curr_x < 60.0f || page == missions.size() / 5)	// do not change page
				{
					float adjustment = time * (anchor_x - curr_x);
					adjustment = adjustment >= 0.05f ? adjustment : 0.05f;
					curr_x += adjustment;
				}
				else if (anchor_x - curr_x > 319.0f)	// arrived at next page
				{
					SypX::ErrorLogger::getLogger() << "Curr page: " << page << "\n";
					page++;
					SypX::ErrorLogger::getLogger() << "New page: " << page << "\n";
					curr_x = anchor_x;
				}
				else	// change page
				{
					float adjustment = time * (320.0f - anchor_x + curr_x);
					adjustment = adjustment >= 0.05f ? adjustment : 0.05f;
					curr_x -= adjustment;	// continue moving
				}
				
			}
			else if (!mousedown && anchor_x < curr_x)	// right swipe
			{
				if (curr_x - anchor_x < 1.0f)	// back to original page
					curr_x = anchor_x;
				else if (curr_x - anchor_x < 60.0f || page == 0)	// do not change page
				{
					float adjustment = time * (curr_x - anchor_x);
					adjustment = adjustment >= 0.05f ? adjustment : 0.05f;
					curr_x -= adjustment;
				}
				else if (curr_x - anchor_x > 319.0f)	// arrived at previous page
				{
					SypX::ErrorLogger::getLogger() << "Curr page: " << page << "\n";
					page--;
					SypX::ErrorLogger::getLogger() << "New page: " << page << "\n";
					curr_x = anchor_x;
				}
				else	// change page
				{
					float adjustment = time * (320.0f - curr_x + anchor_x);
					adjustment = adjustment >= 0.05f ? adjustment : 0.05f;
					curr_x += adjustment;	// continue moving
				}
			}

			float position = (*i).x - anchor_x + curr_x - page * 320.0f;
			(*i).go->move(position, (*i).y);
			(*i).go->draw();

			for (unsigned int j = 0; j < 3; j++)
			{
				(*i).icons[j]->setPosition( SypX::Vec2( position + 40.0f, (*i).icons[j]->getPositionRef().y ) );
				//(*i).icons[j]->getPositionRef().x = position + 40.0f;
				(*i).icons[j]->update();
				render->drawMesh((*i).icons[j]);

				(*i).stars[j]->setPosition( SypX::Vec2( position + 80.0f, (*i).stars[j]->getPositionRef().y ) );
				//(*i).stars[j]->getPositionRef().x = position + 80.0f;
				(*i).stars[j]->update();
				render->drawMesh((*i).stars[j]);
			}
			
			i++;
		}
	}

	void MissionScene::run()
	{
		render->clearScreen();		
		render->setActiveColor(SypX::Vec4(1.0f,1.0f,1.0f,1.0f));
		render->drawMesh(bg);
		handleInput();
		draw(canvas->getElapsedTime());
		back->draw();
		
		canvas->swapBuffers();
		//changeScene(new GameScene(font));
	}

	void MissionScene::goBack(SypX::GuiComponent* g, SypX::Event& e)
	{
		changeScene(new MenuScene(font));
	}

	void MissionScene::goPlay(SypX::GuiComponent* g, SypX::Event& e)
	{
		std::vector<mission>::iterator i = missions.begin();
		int j = 1;

		while (i != missions.end())
		{
			if ((*i).go == g)
				changeScene(new SelectionScene(font, j, (*i)));

			i++;
			j++;
		}
	}
}
